package function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import controller.*;
import dataObject.Brand;
import dataObject.Product;
import dataView.*;
import exception.UserSelectionOutOfRangeException;
import functionHelper.ScoreCalculator;

public class Suggestion extends Function{
	
	private ArrayList<Rank> suggestedProduct = new ArrayList<Rank>();
	private ArrayList<Rank> allProduct = new ArrayList<Rank>();
	private IOPrinter printer;
	private IOInput inputer;
	private ScoreCalculator calculator;
	public Suggestion()
	{
		super("Get Suggestion");
		printer = IOPrinter.getPrinter();
		inputer = IOInput.getInputer();
		calculator = new ScoreCalculator(allProduct);
	}
	
	@Override
	public void perform(ArrayList<Brand> brandList) 
	{
		addProduct(brandList);
		
		printPriorityQuestion(brandList);
		
		boolean rightInput = false;
		while(rightInput==false)
		{
			try {
				String userPriority = inputer.getInputNext();
				calculator.calPriorityScores(userPriority, brandList);
				rightInput=true;
			} catch (UserSelectionOutOfRangeException e) {
				printer.print(e.getMessage());
			} catch (NumberFormatException e){
				printer.print("You must only input number");
			}
		}
		
		
		
		printBudgetQuestion();
		rightInput=false;
		while(rightInput==false)
		{
			try{
				String userBudget = inputer.getInputNext();
				rightInput = handleBudgetLoop(userBudget);
				if(rightInput == true)
					calculator.qualifiedProductByBudget(userBudget);
			} catch (NumberFormatException e){
				printer.print("You must only input number");
			}
		}
		rightInput = false;
		printMonsizeQuestion();
		while(rightInput==false)
		{
			try{
				String userMonsize = inputer.getInputNext();
				rightInput = handleSizeLoop(userMonsize);
				if(rightInput == true)
					calculator.qualifiedProductByMonSize(userMonsize);
			} catch (NumberFormatException e){
				printer.print("You must only input number");
			}
		}
		
		generateSuggestedProduct(brandList);
		//start calculate internal calculation
		calculator.calCameraPixelScores();
		calculator.calBatterySizeScores();
		calculator.calAvailableColor();
		//finish calculate internal calculation
		clearObjectList();

	}
	
	public void addProduct(ArrayList<Brand> brandList)
	{
		for(Brand b:brandList)
		{
			b.genAllProduct(allProduct);
		}
	}
	
	public boolean handleBudgetLoop(String userBudget)
	{
		String[] budget = userBudget.split("-");
		if(budget.length==1)
		{
			return performBudgetCheck(budget[0]);
		}
		else if(budget.length==2)
		{
			for(String s:budget)
			{
				if(performBudgetCheck(s)==false)
					return false;
			}
			return true;
		}
		else
		{
			printer.print("The System only accept 1 input(eg.4000) or range input(4000-5000)");
			return false;
		}
		
	}
	
	public boolean performBudgetCheck(String userBudget)
	{
		if(Double.parseDouble(userBudget)>199 && Double.parseDouble(userBudget)<9000)
		{
			return true;
		}
		else
		{
			printer.print("The Budget range must bigger than $200 and smaller than $9000");
			return false;
		}
	}
	
	public boolean handleSizeLoop(String userMonsize)
	{
		
		String[] size = userMonsize.split("-");
		if(size.length==1)
		{
			return performSizeCheck(size[0]);
		}
		else if(size.length==2)
		{
			for(String s:size)
			{
				if(performSizeCheck(s)==false)
					return false;
			}
			return true;
		}
		else
		{
			printer.print("The System only accept 1 input(eg.4) or range input(4.2-4.5)");
			return false;
		}
	}
	
	public boolean performSizeCheck(String userMonsize)
	{
		if(Double.parseDouble(userMonsize)>1.9 && Double.parseDouble(userMonsize)<8)
		{
			return true;
		}
		else
		{
			printer.print("The Budget range must bigger than 2\" and smaller than 8\"");
			return false;
		}
	}
	
	//////////////////////////////////////////////Print question.
	public void printPriorityQuestion(ArrayList<Brand> brandList)
	{
		printer.print("Please input your brand priority by number.If there are more than one brand name, separate by ','.Type 'All' to select all brand's product.(eg 1,2,3 or all)");
		int counter = 0;
		for(Brand b:brandList)
		{
			counter++;
			printer.printMenuFormat(counter,b.getName());
		}
	}
	
	public void printBudgetQuestion()
	{
		printer.print("Please input your budget.(eg 2000-3500)");
	}
	
	public void printMonsizeQuestion()
	{
		printer.print("Please input your recommended monitor size range.(must be between 2\" to 8\", eg 4-5.5)");
	}
	
	
	public void generateSuggestedProduct(ArrayList<Brand> brandList)
	{
		for(Rank r:allProduct)
		{
			if (r.getQualify()==true)
			{
				suggestedProduct.add(r);
			}
		}
		Collections.sort(suggestedProduct, new Comparator<Rank>()
			{
				@Override
				public int compare(Rank o1, Rank o2) {
					return (o2.getScore())-(o1.getScore());
			}		
		});
		
		
		if(suggestedProduct.size()>0)
		{
			printer.print("Here is the suggestion for you:");
			int counter = 0;
			printer.printProductFormat();
			for(Rank r:suggestedProduct)
			{
				counter++;
				if(counter<10)
					printer.printNoLine(counter+".  ");
				else
					printer.printNoLine(counter+". ");
				r.printList();
			}

		}
		else
		{
			printer.print("Sorry, no product match your request. ");
		}
		
	}
	
	public void clearObjectList()
	{
		//clear the list after all printing
		suggestedProduct.clear();
		allProduct.clear();
	}
	
	//for testing only function
	public Rank getRank(ArrayList<Rank> allProduct,String ProductName)
	{
		for(Rank r:allProduct)
		{
			if(r.getName().equals(ProductName))
				return r;
		}
		return null;
	}
	
	public ArrayList<Rank> getSuggestionList()
	{
		return suggestedProduct;
	}
	 
	public ArrayList<Rank> getAllProduct()
	{
		return allProduct;
	}

}